﻿using BattleFury.Layers;
using BattleFury.Lib.Collections;
using BattleFury.Lib.Graphics;
using BattleFury.Lib.Maps.Data;
using BattleFury.Lib.Tiles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.IO;

namespace BattleFury.Lib.Maps
{
	public class TileLayer
		: BaseLayer, ILayer
	{
		private Random _rnd = new Random();
		private readonly Tile[,] _tiles;

		public string Name { get; set; }
		public Vector2 Size { get; private set; }
		public Vector2 TileSize { get; set; }
        //public bool IsEnabled { get; set; }
        //public bool IsVisible { get; set; }
		public Camera Camera { get; set; }

		public Tile this[int x, int y]
		{
			get { return _tiles[x, y]; }
		}

		public Tile[,] Tiles
		{
			get { return _tiles; }
		}

		public TileLayer(Vector2 size, Vector2 tileSize)
		{
			Size = size;
			TileSize = tileSize;
			IsEnabled = true;
			IsVisible = true;

			_tiles = new Tile[(int)size.X, (int)size.Y];
		}

        //public void Update(GameTime gameTime)
        //{
        //    if (!IsEnabled) return;
        //}

		public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
		{
			if (!IsVisible) return;
			if (Camera == null) return;

			var minX = (int)(Camera.Position.X / TileSize.X);
			var minY = (int)(Camera.Position.Y / TileSize.Y);
			var maxX = (int)((Camera.Position.X + Camera.Size.X) / TileSize.X) + 1;
			var maxY = (int)((Camera.Position.Y + Camera.Size.Y) / TileSize.Y) + 1;

			if (minX < 0) minX = 0;
			if (minY < 0) minY = 0;
			if (maxX > _tiles.GetUpperBound(0) + 1) maxX = _tiles.GetUpperBound(0) + 1;
			if (maxY > _tiles.GetUpperBound(1) + 1) maxY = _tiles.GetUpperBound(1) + 1;

			for (var y = minY; y < maxY; y++)
			{
				for (var x = minX; x < maxX; x++)
				{
					var tile = _tiles[x, y];
					if (tile != null && tile.Index >= 0)
					{
						tile.Camera = Camera;
						tile.Draw(spriteBatch);
					}
				}
			}
		}

		public void Randomize(Texture2D tilesetTexture)
		{
			Randomize(tilesetTexture, 0, (int)((tilesetTexture.Width / TileSize.X) * (tilesetTexture.Height / TileSize.Y)));
		}

		public void Randomize(Texture2D tilesetTexture, int startIndex, int endIndex)
		{
			var tileset = new Tileset(tilesetTexture, TileSize);
			for (var y = 0; y < Size.Y; y++)
			{
				for (var x = 0; x < Size.X; x++)
				{
					var tile = new Tile
					{
						Tileset = tileset,
						Size = TileSize,
						Index = _rnd.Next(startIndex, endIndex),
						Position = new Vector2(x * TileSize.X, y * TileSize.Y)
					};
					_tiles[x, y] = tile;
				}
			}
		}

		public void SetTile(int x, int y, Tile tile)
		{
			_tiles[x, y] = tile;
		}

		public Vector2 GetLocation(Vector2 absoluteLocation)
		{
			return new Vector2(absoluteLocation.X / TileSize.X, absoluteLocation.Y / TileSize.Y);
		}

		public static TileLayer LoadFrom(TilesetCollection tilesets, Vector2 size, TileLayerData data)
		{
			var tileSize = new Vector2(data.TileWidth, data.TileHeight);
			var ret = new TileLayer(size, tileSize);
			ret.Name = data.Name;
			foreach (var tileData in data.Tiles)
			{
				var tilesetName = Path.GetFileName(tileData.Tileset);
				var tileset = tilesets[tilesetName];
				var texture = tileset == null ? RenderEngine.Get().Textures["WhitePixel"] : tileset.Texture;

				var tile = Tile.LoadFrom(texture, tileSize, tileData);
				ret.SetTile(tileData.X, tileData.Y, tile);
			}

			return ret;
		}
	}
}